﻿/* 关于 IB, 您可以参考 http://blog.sina.com.cn/s/blog_604c436d0100o5j0.html.
 * IB 是项目 zsharedcode 的一部分, 您可以参考 http://code.google.com/p/zsharedcode/ 或者 http://blog.sina.com.cn/s/blog_604c436d0100o04s.html.
 * Visual Studio 2010 项目模板请访问 http://blog.sina.com.cn/s/blog_604c436d0100o8gn.html.
 * 所有项目源码托管地址: http://panzer.codeplex.com/.
 * */
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Windows.Forms;

using zoyobar.shared.panzer;
using zoyobar.shared.panzer.web;
using zoyobar.shared.panzer.web.ib;
using zoyobar.shared.panzer.flow;

namespace IBBloggerTemplate
{

	internal class _163Blog
		: Blog
	{
		// 载入 blog 首页的状态名称。
		private const string loadHomePageStateName = "load home page";
		// blog 首页安装 jquery 的状态名称。
		private const string homePageInstallJQueryStateName = "home page install jquery";

		// 首页测试是否登录的状态名称。
		private const string testIsLoginStateName = "test is login";
		// 首页显示登录框的状态名称。
		private const string loginUIStateName = "login ui";
		// 首页登录的状态名称。
		private const string loginStateName = "login";
		// 首页登录成功后的状态名称。
		private const string loginedStateName = "logined";
		// 载入日志编辑页面的状态名称。
		private const string editBlogStateName = "edit blog";
		// 日志编辑页面安装 jquery 的状态名称。
		private const string editBlogPageInstallJQueryStateName = "edit blog page install jquery";
		// 发布日志的状态名称。
		private const string publicBlogStateName = "public blog";
		// TODO: 可以在此处添加新的或者修改上面的页面状态名称。

		// 载入 blog 首页的状态。
		private readonly WebPageState loadHomePageState;
		// blog 首页安装 jquery 的状态。
		private readonly WebPageState homePageInstallJQueryState;

		// 首页测试是否登录的状态。
		private readonly WebPageState testIsLoginState;
		// 首页显示登录框的状态。
		private readonly WebPageState loginUIState;
		// 首页登录的状态。
		private readonly WebPageState loginState;
		// 判断是否登录成功的状态。
		private readonly WebPageState loginedState;

		// 载入日志编辑页面的状态。
		private readonly WebPageState editBlogState;
		// 日志编辑页面安装 jquery 的状态。
		private readonly WebPageState editBlogPageInstallJQueryState;
		// 发布日志的状态。
		private readonly WebPageState publicBlogState;
		// TODO: 可以在此处添加新的或者修改上面的页面状态。

		// 获取编辑页面上标题标签的 jquery 。
		private readonly string titleTagJQuery;
		// 获取编辑页面上文本框标签的 jquery 。
		private readonly string textTagJQuery;
		// 获取编辑页面上分类标签的 jquery 。
		private readonly string catalogTagJS;
		// 获取编辑页面上文章标签的标签的 jquery 。
		private readonly string tagTagJQuery;
		// 获取编辑页面切换源代码标签的 jquery 。
		private readonly string shiftEditModeTagJQuery;

		// 使用已有的设置创建 SinaBlog 。
		internal _163Blog ( WebBrowser browser, string homePage, string editBlogPage, string userName, string password )
			: this ( browser, homePage, userName, Program.Settings["163UserNameTagJQuery"], password, Program.Settings["163PasswordTagJQuery"], Program.Settings["163TestIsLoginTagJQuery"], Program.Settings["163LoginTagJQuery"], editBlogPage, Program.Settings["163TitleTagJQuery"], Program.Settings["163TextTagJQuery"], Program.Settings["163CatalogTagJS"], Program.Settings["163TagTagJQuery"], Program.Settings["163PublicTagJQuery"], Program.Settings["163ShiftEditModeTagJQuery"] )
		{ }
		internal _163Blog ( WebBrowser browser, string homePage, string userName, string userNameTagJQuery, string password, string passwordTagJQuery, string testIsLoginTagJQuery, string loginTagJQuery, string editBlogPage, string titleTagJQuery, string textTagJQuery, string catalogTagJS, string tagTagJQuery, string publicTagJQuery, string shiftEditModeTagJQuery )
			: base ( browser, homePage, userName, userNameTagJQuery, password, passwordTagJQuery )
		{

			if ( string.IsNullOrEmpty ( testIsLoginTagJQuery ) || string.IsNullOrEmpty ( loginTagJQuery ) || string.IsNullOrEmpty ( editBlogPage ) || string.IsNullOrEmpty ( titleTagJQuery ) || string.IsNullOrEmpty ( textTagJQuery ) || string.IsNullOrEmpty ( catalogTagJS ) || string.IsNullOrEmpty ( tagTagJQuery ) || string.IsNullOrEmpty ( publicTagJQuery ) || string.IsNullOrEmpty ( shiftEditModeTagJQuery ) )
				throw new ArgumentNullException ( );

			this.titleTagJQuery = titleTagJQuery;
			this.textTagJQuery = textTagJQuery;
			this.catalogTagJS = catalogTagJS;
			this.tagTagJQuery = tagTagJQuery;
			this.shiftEditModeTagJQuery = shiftEditModeTagJQuery;

			// 载入 blog 首页的状态。
			this.loadHomePageState = new WebPageState (
				loadHomePageStateName,
				new NavigateAction ( homePage, 5 ), // 这里跳转到 blog 首页，并等待 5 秒钟。
				new WebPageNextStateSetting ( // 这里表示，当载入 blog 首页后，自动转到安装 jQuery 的状态。
					homePageInstallJQueryStateName,
					true
				),
				new UrlCondition ( homePage, homePage, StringCompareMode.StartWith ) // 这里表示当 blog 页面载入后，表示状态完成。
				);

			// blog 首页安装 jquery 的状态。
			this.homePageInstallJQueryState = new WebPageState (
				homePageInstallJQueryStateName,
				//	TODO: 在此处修改为自定义的 jQuery 脚本下载地址。之前使用载入本地的 jquery 脚本由于编码问题出现错误，现使用另外的方式加载。
				new WebPageAction[] {
					new InstallTraceAction ( ), // 这里安装跟踪脚本，是 jQuery 所需的脚本。
					new InstallJavaScriptAction ( Properties.Resources.jquery_1_5_min, "jsJQuery_1_5" ) // 这里安装 jQuery 1.5 。
				},
				new WebPageNextStateSetting ( // 这里表示，当载入 jQuery 后，自动转到判断是否登录的状态。
					testIsLoginStateName,
					true
				)
				);

			// 首页测试是否登录的状态。
			this.testIsLoginState = new WebPageState (
				testIsLoginStateName,
				new WebPageNextStateSetting ( // 这里表示，如果已经登录直接跳转到编辑日志的页面状态。
					editBlogStateName,
					true
				),
				new WebPageNextStateSetting ( // 这里表示，如果没有登录跳转到准备登录的页面状态。
					loginUIStateName,
					true
				),
				new JQueryCondition ( "jquery test", JQuery.Create ( testIsLoginTagJQuery ).Length ( ), "0" ), // 这里表示，如果指定的标签存在，那么认为没有登录。
				2 // 如果 2 秒后，仍然检测为没有登录，则认为登录状态失败，准备登录。
				);

			// 首页显示登录框的状态。
			this.loginUIState = new WebPageState (
				loginUIStateName,
				new WebPageAction[] {
					new ExecuteJQueryAction ( JQuery.Create ( testIsLoginTagJQuery ).Attr ( "'id'", "'isLoginTag'" ) ),
					new ExecuteJavaScriptAction ( "document.getElementById('isLoginTag').click();" ) // 这里的两个动作表示点击登录按钮，显示登录界面，也可以使用 JQuery 类的 Trigger 方法，但不适用于 a 标签，但先为登录按钮增加了 id 属性，为了让后来的 javascript 获得 a 标签。
				},
				new WebPageNextStateSetting ( // 这里表示，如果登录界面已经显示则跳转到填写信息并登录的页面状态。
					loginStateName,
					true
				),
				new JQueryCondition ( "jquery user name", JQuery.Create ( userNameTagJQuery ).Length ( ), 1 ) // 这里表示，如果用户名标签存在，则认为登录界面已经显示。
				);

			// 首页登录的状态。
			this.loginState = new WebPageState (
				loginStateName,
				new WebPageAction[] {
					new ExecuteJQueryAction ( JQuery.Create ( userNameTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( userName ) ) ) ), // 这里表示填写用户名。
					new ExecuteJQueryAction ( JQuery.Create ( passwordTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( password ) ) ) ), // 这里表示填写密码。
					new ExecuteJQueryAction ( JQuery.Create ( loginTagJQuery ).Trigger ( "'click'" ) ) // 这里表示点击登录按钮，也可以使用 JQuery 类的 Trigger 方法，但不适用于 a 标签。
				},
				new WebPageNextStateSetting ( // 这里表示，点击登录后进入判断是否登录成功的状态。
					loginedStateName,
					true
				)
				);

			// 判断是否登录成功的状态。
			this.loginedState = new WebPageState (
				loginedStateName,
				new WebPageNextStateSetting ( // 这里表示，如果登录成功则进入载入编辑页面的状态。
					editBlogStateName,
					true
				),
				new ExecuteJavaScriptAction ( "alert('登录失败, 用户名或者密码错误!');" ), // 如果登录不成功，则弹出对话框。
				new UrlCondition ( homePage, homePage, StringCompareMode.StartWith ), // 如果页面重新载入一次，则认为登录成功。
				// TODO: 如果网速过慢，可以延长超时时间。
				10 // 如果 10 秒钟页面还没有重新载入，则认为登录失败。
				);

			// 载入日志编辑页面的状态。
			this.editBlogState = new WebPageState (
				editBlogStateName,
				new NavigateAction ( editBlogPage, 5 ), // 载入日志编辑页面，并等待 5 秒钟。
				new WebPageNextStateSetting ( // 这里表示，载入成功后，进入安装 jQuery 的状态。
					editBlogPageInstallJQueryStateName,
					true
				),
				new UrlCondition ( editBlogPage, editBlogPage, StringCompareMode.StartWith ) // 但编辑页面载入时，认为状态完成。
				);

			// 日志编辑页面安装 jquery 的状态。
			this.editBlogPageInstallJQueryState = new WebPageState (
				editBlogPageInstallJQueryStateName,
				//	TODO: 在此处修改为自定义的 jQuery 脚本下载地址。之前使用载入本地的 jquery 脚本由于编码问题出现错误，现使用另外的方式加载。
				new WebPageAction[] {
					new InstallTraceAction ( ), // 这里安装跟踪脚本，是 jQuery 所需的脚本。
					new InstallJavaScriptAction ( Properties.Resources.jquery_1_5_min, "jsJQuery_1_5" ) // 这里安装 jQuery 1.5 。
				},
				new WebPageNextStateSetting ( // 安装 jQuery 后，进入日志的发布状态。
					publicBlogStateName,
					true
				)
				);

			// 发布日志的状态。
			this.publicBlogState = new WebPageState (
				publicBlogStateName,
				new WebPageAction[] {
					new EmptyAction ( ), // 这里是填写标题，由于标题需要用户输入，这里此命令设置为空命令。
					new EmptyAction ( ), // 这里是是否切换显示源代码，同上也是空命令。
					new EmptyAction ( ), // 这里是填写内容，由于内容需要用户输入，这里此命令设置为空命令。
					new EmptyAction ( ), // 这里是填写分类，由于分类需要用户输入，这里此命令设置为空命令。
					new EmptyAction ( ),  // 这里是填写标签，由于标签需要用户输入，这里此命令设置为空命令。
					new ExecuteJQueryAction ( JQuery.Create ( publicTagJQuery ).Trigger ( "'click'" ) )
				}
				);

			// 创建核心 IEBrowser。
			this.ie = new IEBrowser ( browser, new WebPageState[] { this.loadHomePageState, this.homePageInstallJQueryState, this.testIsLoginState, this.loginUIState, this.loginState, this.loginedState, this.editBlogState, this.editBlogPageInstallJQueryState, this.publicBlogState } );
		}

		internal override void WriteBlog ( string title, string textHTML, string catalog, string tag, bool isShiftEditMode )
		{
			// 点击发布按钮后，设置发布日志状态的各个命令。
			this.publicBlogState.StartActions[0] = new ExecuteJQueryAction ( JQuery.Create ( this.titleTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( title ) ) ) ); // 设置填写标题的命令。

			// 设置是否切换显示源代码的命令。
			if ( isShiftEditMode )
				this.publicBlogState.StartActions[1] = new ExecuteJQueryAction ( JQuery.Create ( this.shiftEditModeTagJQuery ).Trigger ( "'click'" ) );
			else
				this.publicBlogState.StartActions[1] = new EmptyAction ( );

			this.publicBlogState.StartActions[2] = new ExecuteJQueryAction ( JQuery.Create ( this.textTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( textHTML ) ) ) ); // 设置填写内容的命令。
			this.publicBlogState.StartActions[3] = new ExecuteJavaScriptAction ( string.Format ( this.catalogTagJS, IEBrowser.EscapeCharacter ( catalog ) ) ); // 设置填写分类的命令。
			this.publicBlogState.StartActions[4] = new ExecuteJQueryAction ( JQuery.Create ( this.tagTagJQuery ).Val ( string.Format ( "'{0}'", IEBrowser.EscapeCharacter ( tag ) ) ) ); // 设置填写标签的命令。

			// 从载入首页的状态开始。
			this.ie.IEFlow.JumpToState ( loadHomePageStateName );
		}

	}

}
